#pragma once
#include<iostream>
#include<sys/socket.h>
#include<sys/types.h>
#include<netinet/in.h>
#include<unistd.h>
#include<arpa/inet.h>
#include<pthread.h>
#include"log.hpp"

using namespace std;

#define PORT 8080


class TcpServer{

private:
    TcpServer(int port=PORT)
    :_port(port),_listensock(-1)
    {


    }

    TcpServer(const TcpServer&s)=delete;
    TcpServer &operator=(const TcpServer&s)=delete;

public:

    static TcpServer*getinstance(int port){
        
        if(svr==nullptr){
            pthread_mutex_lock(&lock);
            if(svr==nullptr){
                svr=new TcpServer(port);
                svr->InitServer();
            }

            pthread_mutex_unlock(&lock);
        }

        return svr;
    }

    void InitServer(){
        Socket();
        Bind();
        Listen();

        LOG(INFO,"tcp_server init successful");
    }

    void Socket(){
        _listensock=socket(AF_INET,SOCK_STREAM,0);
        if(_listensock<0){
            LOG(fatal,"socket failed");
            exit(1);
        }
        int opt=1;
        setsockopt(_listensock,SOL_SOCKET,SO_REUSEADDR,&opt,sizeof(opt));
        LOG(INFO,"create socket successful");
    }

    void Bind(){

        struct sockaddr_in local;
        local.sin_family=AF_INET;
        local.sin_port=htons(_port);
        local.sin_addr.s_addr=INADDR_ANY;
        if(bind(_listensock,(sockaddr*)&local,sizeof(local))<0) {
            exit(2);
        }
        LOG(INFO,"bind successful");

    }

    void Listen(){
        if(listen(_listensock,5)<0){
            LOG(FATAL,"listen failed");
            exit(3);
        }
        LOG(INFO,"listen successful");
    }

    int Accept(){
        sockaddr_in client;
        socklen_t len=sizeof(client);
        int newfd=accept(_listensock,(sockaddr*)&client,&len);
        
        
        if(newfd<0){
            LOG(FATAL,"accept failed");
            exit(5);
        }

        else {
            LOG(INFO,"accept successful");
            cout<<"newfd="<<newfd<<endl;
            return newfd;
        }
        
        // else{
        //     char buffer[1024*10]={0};
        //     int n=read(newfd,buffer,sizeof(buffer));
        //     if(n>0){
        //         buffer[n]='\0';

        //         cout<<buffer<<endl;
        //     }
        // }
    }

    int Sock(){
        return _listensock;
    }

    ~TcpServer(){
        if(_listensock)close(_listensock);
    }
private:    

    int _port;
    int _listensock;
    static TcpServer *svr;
    static pthread_mutex_t lock;
    
};


TcpServer*TcpServer::svr=nullptr;
pthread_mutex_t TcpServer::lock=PTHREAD_MUTEX_INITIALIZER;